#pragma once

#include<iostream>
#include<time.h>
#include<stdarg.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<unistd.h>

#define SIZE 1024

/*
log:日志时间、日志等级(log level)、日志内容、文件名称和行号

log level: 
Info->常规消息
Warning->报警消息
Error->比较严重，可能需要立即处理
Fatal->致命的
Debug->调试

*/
//log level
#define Info    0
#define Debug   1
#define Warning 2
#define Error   3
#define Fatal   4

//printMethod
#define Screen    1
#define Onefile   2
#define Classfile 3

#define LogFile "log.txt"


class Log
{
public:
    Log()
    {
        printMethod = Screen;
        path = "./log/";
    }
    void Enable(int method)
    {
        printMethod = method;
    }
    std::string levelToString(int level)
    {
        switch (level)
        {
        case Info:
            return "Info";
        case Debug:
            return "Debug";
        case Warning:
            return "Warning";
        case Error:
            return "Error";
        case Fatal:
            return "Fatal";
        default:
            return "None";
        }
    }

    // void logmessage(int level, const char *format, ...)
    // {
    //     time_t t = time(nullptr);
    //     struct tm *ctime = localtime(&t);
    //     char leftbuffer[SIZE];
    //     snprintf(leftbuffer, sizeof(leftbuffer),
    //     "[%s][%d-%d-%d %d:%d:%d]",
    //     levelToString(level).c_str(), ctime->tm_year+1900, 
    //     ctime->tm_mon+1, ctime->tm_mday, ctime->tm_hour,
    //     ctime->tm_min, ctime->tm_sec
    //     );

    //     va_list s;
    //     va_start(s, format);
    //     char rightbuffer[SIZE];
    //     vsnprintf(rightbuffer, sizeof(rightbuffer),
    //     format, s
    //     );
    //     va_end(s);

    //     //格式：默认部分+自定义部分
    //     char logtxt[SIZE*2];
    //     snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);

    //     //printf();//temporarily print
    //     printLog(level, logtxt);
    // }

    void printLog(int level, const std::string &logtxt)
    {
        switch(printMethod)
        {
        case Screen:
            std::cout << logtxt << std::endl;
            break;
        case Onefile:
            printOneFile(LogFile, logtxt);
            break;
        case Classfile:
            printClassFile(level, logtxt);
            break;
        default:
            break;
        }
    }
    void printOneFile(const std::string &logname, const std::string &logtxt)
    {
        std::string _logname = path + logname;
        int fd = open(_logname.c_str(), O_WRONLY|O_CREAT|O_APPEND, 0666); // "log.txt"
        if (fd < 0){
            return;
        }
        write(fd, logtxt.c_str(), logtxt.size());
        close(fd);
    }
    void printClassFile(int level, const std::string &logtxt)
    {
        std::string filename = LogFile;
        filename += ".";
        filename += levelToString(level); //"log.txt.Debug/Warning/Fatal"
        printOneFile(filename, logtxt);
    }

    ~Log()
    {
    }

    void operator()(int level, const char *format, ...)
    {
        time_t t = time(nullptr);
        struct tm *ctime = localtime(&t);
        char leftbuffer[SIZE];
        snprintf(leftbuffer, sizeof(leftbuffer),"[%s][%d-%d-%d %d:%d:%d]",
        levelToString(level).c_str(), ctime->tm_year+1900, ctime->tm_mon+1, 
            ctime->tm_mday, ctime->tm_hour,ctime->tm_min, ctime->tm_sec
        );

        va_list s;
        va_start(s, format);
        char rightbuffer[SIZE];
        vsnprintf(rightbuffer, sizeof(rightbuffer), format, s );
        va_end(s);

        //格式：默认部分+自定义部分
        char logtxt[SIZE*2];
        snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);

        //printf();//temporarily print
        printLog(level, logtxt);
    }

private:
    int printMethod;
    std::string path;
};


// int sum(int n, ...)
// {
//     va_list s; // char*
//     va_start(s, n); //initialize s

//     int sum = 0;
//     while(n)
//     {
//         sum += va_arg(s, int); // printf("hello %d, hello %s, hello %c, hello %d,", 1, "hello", 'c', 123);
//         n--;
//     }

//     va_end(s); //s = NULL
//     return sum;
// }


